using System;
using System.Collections;
using Curriculum.LectoresXML.LectorMetadatos;
using Curriculum.Metadatos.ClasesMetadatos;
using Curriculum.Modelo.Clases;
using Curriculum.Services;
using Curriculum.Manejadores;
using Curriculum.Utiles;
using Modelo.Clases.Listas;
using Utiles;
using Atributo = Curriculum.LectoresXML.LectorMetadatos.Atributo;

namespace Curriculum.Services
{
	/// <summary>
	/// Summary description for VersionMetadatosService.
	/// </summary>
	public class VersionMetadatosService : ServiceBase
	{
		public VersionMetadatosService()
		{
		}
		/// <summary>
		/// Retorna una lista de todos los objetos VersionMetadato
		/// </summary>
		/// <returns></returns>
		public IList ObtenerVersionesMetadatos()
		{
			return dataManager.GetAllObjects(typeof(VersionMetadato));			
		}

		/// <summary>
		/// Devuelve los antecedentes que no tienen padre
		/// Tomando como ref. el enunciado de pelu del TP1
		/// vienen a ser: "Curso","En Pedagogia", etc.
		/// </summary>
		/// <returns></returns>
		public IList ObtenerNodosRaiz()
		{
			return this.dataManager.GetAntecedentesMetadatoHuerfanos();
		}
		/// <summary>
		/// Dada una version de metadatos y un id de 
		/// un antecedente metadato, devuelve una
		/// lista de antecedentes hijos
		/// </summary>
		/// <param name="antecedenteMetadatoPadreId"></param>
		/// <returns></returns>
		public IList ObtenerNodosHijo(string antecedenteMetadatoPadreId)
		{
			return this.dataManager.GetNodosMetadatoHijos(antecedenteMetadatoPadreId);			
		}
		

		#region - AntecedenteMetadato -
		
		/// <summary>
		/// Dado un id de antecedenteMetadato, devuelve
		/// un antecedente Metadato
		/// </summary>
		/// <param name="antecedenteMetadatoId"></param>
		/// <returns></returns>
		public AntecedenteMetadato ObtenerAntecedenetMetadato(object antecedenteMetadatoId)
		{
			return dataManager.GetById(typeof(AntecedenteMetadato), antecedenteMetadatoId.ToString()) as AntecedenteMetadato;
		}

		/// <summary>
		/// Dado un id de antecedenteMetadato, devuelve
		/// un antecedente Metadato desde su raiz hasta la hoja
		/// </summary>
		/// <param name="antecedenteMetadatoIdHoja"></param>
		/// <returns></returns>
		public AntecedenteMetadato ObtenerAntecedenteMetadatoDesdeRaiz(string antecedenteMetadatoIdHoja)
		{
			AntecedenteMetadato antecedenteMetadato = dataManager.GetAntecedenteMetadato(antecedenteMetadatoIdHoja);
			Stack pilaIds = new Stack();

			pilaIds.Push(antecedenteMetadatoIdHoja);

			// TODO: ver si el padre es null o string.empty						
			while ((antecedenteMetadato != null) && (antecedenteMetadato.IdPadre != null))
			{
				antecedenteMetadato = dataManager.GetAntecedenteMetadato(antecedenteMetadato.IdPadre);				
				pilaIds.Push(antecedenteMetadato.Id);
			}
			
			AntecedenteMetadato anteRaiz = dataManager.GetAntecedenteMetadato(pilaIds.Pop().ToString());
			
			AntecedenteMetadato antePadreActual = anteRaiz;			
			AntecedenteMetadato anteHijoActual = null;

			if (antePadreActual.AntecedenteMetadatos != null)
			{
				antePadreActual.AntecedenteMetadatos = new AntecedenteMetadato[1];
			}

			while (pilaIds.Count > 0)
			{
				anteHijoActual = dataManager.GetAntecedenteMetadato(pilaIds.Pop().ToString());
				antePadreActual.AntecedenteMetadatos.SetValue(anteHijoActual, 0);
				antePadreActual = anteHijoActual;
		
				if (antePadreActual.AntecedenteMetadatos != null)
				{
					antePadreActual.AntecedenteMetadatos = new AntecedenteMetadato[1];
				}
			}
						
			return anteRaiz;
		}		

		/// <summary>
		/// Crea un AntecedenteMetadato
		/// </summary>
		/// <param name="antecedenteMetadato"></param>
		/// <returns>retorna el id con el que se dio de alta el antecedente Metadato</returns>
		public object CrearAntecedenteMetadato(AntecedenteMetadato antecedenteMetadato)
		{					
			AtributoMetadato[] atributosNuevosPorId = antecedenteMetadato.AtributoMetadatos;
			antecedenteMetadato.AtributoMetadatos = new AtributoMetadato[0];			
				
			AgregarAtributosNuevosPorId(antecedenteMetadato, atributosNuevosPorId);
			base.Crear(antecedenteMetadato);
	
			// se lo agrego al padre a la lista de hijos
			if (antecedenteMetadato.IdPadre != null)
			{
				AntecedenteMetadato anteMetaPadre = dataManager.GetAntecedenteMetadato( antecedenteMetadato.IdPadre );
				if (anteMetaPadre.AntecedenteMetadatos == null)
				{
					anteMetaPadre.AntecedenteMetadatos = new AntecedenteMetadato[0];
				}
				
				ArrayList antecedentesHijos = new ArrayList();
				foreach (AntecedenteMetadato anteMetaHijo in anteMetaPadre.AntecedenteMetadatos)
				{
					antecedentesHijos.Add(anteMetaHijo);
				}

				// agrego el antecedente actual a la lista de hijos.
				antecedentesHijos.Add(antecedenteMetadato);
				anteMetaPadre.AntecedenteMetadatos = new AntecedenteMetadato[antecedentesHijos.Count];
				antecedentesHijos.CopyTo(anteMetaPadre.AntecedenteMetadatos);			

				//Modificar(anteMetaPadre);
				dataManager.GuardarAntecedenteMetadato((anteMetaPadre));
			}			

			return antecedenteMetadato.Id;
		}
		/// <summary>
		/// Modifica un AntecedenteMetadato
		/// </summary>
		/// <param name="antecedenteMetadato"></param>
		/// <returns>retorna el id del antecedente Metadato</returns>
		public object ModificarAntecedenteMetadato(AntecedenteMetadato antecedenteMetadato)		
		{			
			AntecedenteMetadato antMeta = dataManager.GetAntecedenteMetadato(antecedenteMetadato.Id);

			// Le actualizo los atributos, 
			// En el AntecedenteMetadato solo vienen los nuevos
			AgregarAtributosNuevosPorId(antMeta, antecedenteMetadato.AtributoMetadatos);

			// Actualizo el nombre
			antMeta.Nombre = antecedenteMetadato.Nombre;		

			// actualizo en la bd
			dataManager.GuardarAntecedenteMetadato(antMeta);
			return antMeta.Id;
		}
		/// <summary>
		/// Elimina un AntecedenteMetadato
		/// </summary>
		/// <param name="antecedenteMetadatoId">id del antecedente Metadato que se quiere eliminar</param>
		/// <returns></returns>
		public void EliminarAntecedenteMetadato(object antecedenteMetadatoId)
		{
			base.Eliminar(typeof(AntecedenteMetadato), antecedenteMetadatoId);
		}

		/// <summary>
		/// Devuelve todos los antecedentes metadatos
		/// </summary>
		public IList ObtenerAntecedentesMetadatos()
		{
			return dataManager.GetAllObjects(typeof(AntecedenteMetadato));
		}


		public IList ObtenerAntecedentesMetadatoConAtributoTipoLista()
		{
			IList lista = dataManager.GetAntecedentesMetadatoConAtributosTipoLista();
			
			if (lista != null) ((ArrayList)lista).Sort(new GenericComparer("Nombre", true));			

			return lista;
		}
		#endregion - AntecedenteMetadato -

		#region - AtributoMetadato -

		/// <summary>
		/// Dado un id de atributoMetadato, devuelve
		/// un atributo Metadato
		/// </summary>
		/// <param name="atributoMetadatoId"></param>
		/// <returns></returns>
		public AtributoMetadato ObtenerAtributoMetadato(object atributoMetadatoId)
		{
			return dataManager.GetById(typeof(AtributoMetadato), atributoMetadatoId.ToString()) as AtributoMetadato;
		}

		/// <summary>
		/// Crea un AtributoMetadato
		/// </summary>
		/// <param name="atributoMetadato"></param>
		/// <returns>retorna el id con el que se dio de alta el atributo Metadato</returns>
		public object CrearAtributoMetadato(AtributoMetadato atributoMetadato)
		{						
			// lo creo en la base, me retorna el id de la instancia creada.
			return base.Crear(atributoMetadato).ToString();					
		}
		/// <summary>
		/// Modifica un AtributoMetadato
		/// </summary>
		/// <param name="atributoMetadato"></param>
		/// <returns>retorna el id del atributo Metadato</returns>
		public object ModificarAtributoMetadato(AtributoMetadato atributoMetadato)
		{	
			// actualizo la instancia de la base
			return base.Modificar(atributoMetadato);
		}
		/// <summary>
		/// Elimina un AtributoMetadato
		/// </summary>
		/// <param name="atributoMetadatoId">id del atributo Metadato que se quiere eliminar</param>
		/// <returns></returns>
		public void EliminarAtributoMetadato(object atributoMetadatoId)
		{
			base.Eliminar(typeof(AtributoMetadato), atributoMetadatoId);
		}

		public IList GetAtributos(string nombre, string tipoId)
		{	
			IList atributos = dataManager.GetAtributos(nombre, tipoId);

			if (atributos != null)
			{
				((ArrayList)atributos).Sort(new GenericComparer("Nombre", true));
			}
		
			return atributos;
		}

		public IList ObtenerAtributosTipoListaDeAntecedente(string antecedenteMetadatoId)
		{
			AntecedenteMetadato antecedenteMetadato = dataManager.GetAntecedenteMetadato(antecedenteMetadatoId);
			ArrayList atributosMetadatoTipoLista = new ArrayList();

			if (antecedenteMetadato != null)
			{
				foreach (AtributoMetadato atributoMetadato in antecedenteMetadato.AtributoMetadatos)
				{								
					if (atributoMetadato.IdTipoDato.Equals(Constants.ID_ATRIBUTOS_TIPO_LISTA))
					{
						atributosMetadatoTipoLista.Add(atributoMetadato);
					}
				}
			}

			if (atributosMetadatoTipoLista != null) 
				atributosMetadatoTipoLista.Sort(new GenericComparer("Nombre", true));

			return atributosMetadatoTipoLista;
		}

		public IList ObtenerAtributosTipoLista()
		{
			return dataManager.GetAtributos(string.Empty, Constants.ID_ATRIBUTOS_TIPO_LISTA);
		}
		public IList GetAllAtributos()
		{
			IList atributos = dataManager.GetAllAtributos();

			if (atributos != null)
			{
				((ArrayList)atributos).Sort(new GenericComparer("Nombre", true));
			}
		
			return atributos;
		}

		#endregion - AtributoMetadato -

		#region - Tipos De Datos -

		/// <summary>
		/// Obtiene el tipo de atributo
		/// </summary>
		/// <param name="idTipoDato"></param>
		/// <returns></returns>
		public string ObtenerTipo(string idTipoDato)
		{
			return this.GetTipoDatoPorId(idTipoDato).tipo;
		}
			
		public IList GetTiposDatos()
		{
			ManejadorTiposDatos manTiposDatos = new ManejadorTiposDatos();
			ArrayList lista = new ArrayList();
			
			if ((manTiposDatos.TiposDatos != null) && (manTiposDatos.TiposDatos.Tipo != null))
			{
				foreach (Tipo tipoDato in manTiposDatos.TiposDatos.Tipo)
				{
					TipoDato tipoDatoExt = new TipoDato(tipoDato.id, tipoDato.tipo, tipoDato.Value);
					lista.Add(tipoDatoExt);
				}
			}

			return lista;
		}


		public Tipo	GetTipoDatoPorId(string idTipoDato)
		{
			ManejadorTiposDatos manTiposDatos = new ManejadorTiposDatos();
			return manTiposDatos.ObtenerTipoById(idTipoDato);
		}
		

		#endregion

		#region - Lista Valores -
		
		public IList GetListaValores(string idAntecedente, string idAtributo)
		{
			return dataManager.GetListaValores(idAntecedente, idAtributo);
		}

		public object CrearItemListaValores(string idAntecedenteMetadato, string idAtributoMetadato, string valor)
		{						
			// Creo el Item en la Base
			ItemListaValores itemListaValores = new ItemListaValores();
			itemListaValores.AntecedenteMetadato = dataManager.GetById(typeof(AntecedenteMetadato), idAntecedenteMetadato) as AntecedenteMetadato;
			itemListaValores.AtributoMetadato = dataManager.GetById(typeof(AtributoMetadato), idAtributoMetadato) as AtributoMetadato;
			itemListaValores.Valor = valor;
			Crear(itemListaValores);			

			return itemListaValores.Id;
		}

		public object CrearItemListaValores(ItemListaValores itemListaValores)
		{				
			// Creo el Item en la Base		
			Crear(itemListaValores);

			return itemListaValores.Id;
		}

		public object ModificarItemListaValores( ItemListaValores itemListaValores)
		{															
			// actualizo la instancia de la base			
			return base.Modificar(itemListaValores);
		}

		public void EliminarItemListaValores(object itemListaValoresId)
		{
			base.Eliminar(typeof(ItemListaValores), itemListaValoresId);
		}

		public ItemListaValores ObtenerItemListaValores(object itemListaValoresId)
		{
			return base.ObtenerObjetoPorId(typeof(ItemListaValores), itemListaValoresId.ToString()) as ItemListaValores;
		}

		#endregion	

		#region Overrides

		protected override Type GetMyObjectType()
		{
			return typeof(VersionMetadato);
		}

		#endregion

		private void AgregarAtributosNuevosPorId(AntecedenteMetadato antecedenteMetadato, AtributoMetadato[] atributosNuevos)
		{			
			if (atributosNuevos != null)
			{
				ArrayList listaAuxiliar = new ArrayList(antecedenteMetadato.AtributoMetadatos);

				foreach (AtributoMetadato at in atributosNuevos)
				{
					AtributoMetadato atributoCompleto = dataManager.GetAtributoMetadatoById(at.Id);
					listaAuxiliar.Add(atributoCompleto);
				}

				antecedenteMetadato.AtributoMetadatos = new AtributoMetadato[listaAuxiliar.Count];
				listaAuxiliar.CopyTo(antecedenteMetadato.AtributoMetadatos);
			}
		}
		

	}
}
